package com.xinyin.aiqinhaiback.task;


import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.serotonin.modbus4j.exception.ErrorResponseException;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.xinyin.aiqinhaiback.Utils.InformationTreeUtil;
import com.xinyin.aiqinhaiback.Utils.JsonUtil;
import com.xinyin.aiqinhaiback.common.ConfigCache;
import com.xinyin.aiqinhaiback.common.ResponseResult;
import com.xinyin.aiqinhaiback.config.ModbusConfig;
import com.xinyin.aiqinhaiback.mapper.InformationMapper;
import com.xinyin.aiqinhaiback.modbus.Modbus4jUtils;
import com.xinyin.aiqinhaiback.modbus.ModbusUtil;
import com.xinyin.aiqinhaiback.modbus.SimpleMasterExample;
import com.xinyin.aiqinhaiback.model.entity.*;
import com.xinyin.aiqinhaiback.service.InformationService;
import com.xinyin.aiqinhaiback.websocket.AlarmWebSocket;
import com.xinyin.aiqinhaiback.websocket.MyWebSocket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

@Component
@EnableScheduling
public class TimeTask {
    private static Logger logger = LoggerFactory.getLogger(TimeTask.class);
    @Autowired
    private InformationService informationService;
    @Resource
    private InformationMapper informationMapper;


    ModBusDevice modBusDeviceLog = null;

    @PostConstruct
    public void init() {
        try {
            ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
            // 使用Lambda表达式传递参数
            scheduler.scheduleAtFixedRate(() -> logData(modBusDeviceLog), 0, 600, TimeUnit.SECONDS);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void logData(ModBusDevice modBusDevice) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        logger.info("保存历史数据: " + formatter.format(new Date().getTime()));
        if (modBusDevice != null) {
            List<Information> informationList = modBusDevice.getInformationList();
            List<SensorInfo> sensorInfoList = modBusDevice.getSensorInfoList();
            List<DeviceHistoryData> deviceHistoryDatalist = new ArrayList<>();
            List<SensorHistoryData> sensorHistoryDataList = new ArrayList<>();
            for (Information item : informationList) {
                if (item.getIsRecord() == 1) {
                    DeviceHistoryData deviceHistoryData = new DeviceHistoryData();
                    deviceHistoryData.setId(UUID.randomUUID().toString());
                    deviceHistoryData.setValue(item.getValue());
                    deviceHistoryData.setInformationId(item.getId());
                    deviceHistoryDatalist.add(deviceHistoryData);
                }
            }

            for (SensorInfo item : sensorInfoList) {
                if (item.getIsRecord() == 1) {
                    SensorHistoryData sensorHistoryData = new SensorHistoryData();
                    sensorHistoryData.setId(UUID.randomUUID().toString());
                    sensorHistoryData.setValue(item.getValue());
                    sensorHistoryData.setSensorId(item.getId());
                    sensorHistoryDataList.add(sensorHistoryData);
                }
            }

            System.out.println(deviceHistoryDatalist);
            if (CollectionUtils.isNotEmpty(deviceHistoryDatalist)) {
                informationService.addDeviceHistoryDataList(deviceHistoryDatalist);
            }
            if (CollectionUtils.isNotEmpty(sensorHistoryDataList)) {
            informationService.addSensorHistoryDataList(sensorHistoryDataList);
            }
        }
    }

    @Scheduled(cron = "0/6 * * * * ?")
    private void showData() throws ModbusTransportException, ErrorResponseException, ModbusInitException, ExecutionException, InterruptedException {
        //test();
        try {
            try {
                ModBusDevice modBusDevice = null;
                try {
                    //modbus获取数据
                    modBusDevice = ModbusUtil.getData();
                    //System.out.println("读取modbus 数据:" + modBusDevice);
                } catch (Exception e) {
                    System.out.println("modbus getData()失败" + e);
                    logger.error("modbus getData()失败", e);
                }
                if (modBusDevice == null) {
                    logger.error("modbusDevice is null");
                    return;
                }

                List<Information> informationList = modBusDevice.getInformationList();
                dealAlarm(modBusDevice);//处理报警信息
                this.modBusDeviceLog = modBusDevice;//处理历史信息
                //处理树形结构
                List<Map<String, Object>> resList = InformationTreeUtil.getData(informationList);
                //统计设备数量
                Map<String, Device> deviceMap = new HashMap<>();
                deviceMap.put("冷源机组", new Device("机组", 0, 0));
                deviceMap.put("冷却泵", new Device("冷却泵", 0, 0));
                deviceMap.put("冷冻泵", new Device("冷冻泵", 0, 0));
                deviceMap.put("冷却塔", new Device("冷却塔", 0, 0));
                deviceMap.put("循环泵", new Device("循环泵", 0, 0));
                deviceMap.put("锅炉", new Device("锅炉", 0, 0));
                //查询设备
                List<DeviceStatus> deviceNameList = informationService.getDevicesName();
                // 初始化deviceStatusMap
                Map<String, List<DeviceStatus>> deviceStatusMap = deviceMap.keySet().stream()
                        .collect(Collectors.toMap(
                                key -> key,
                                key -> deviceNameList.stream()
                                        .filter(name -> name.getDeviceName().replaceAll("\\d", "").equals(key))
                                        .collect(Collectors.toList())
                        ));
//					deviceMap.put("热水泵", new Device("热水泵", 0, 0));
                int runStatus = 0;
                int errorStatus = -1;
                for (Information information : informationList) {
                    String reDeviceName = information.getDeviceName().replaceAll("\\d", "");
                    if (deviceMap.containsKey(reDeviceName) && "设备状态".equals(information.getClassify()) && information.getInformationName().contains("运行状态")) {
                        deviceMap.put(reDeviceName, new Device(reDeviceName, deviceMap.get(reDeviceName).getRunMount(), deviceMap.get(reDeviceName).getTotalMount() + 1));
                        if (information.getValue() != null && Boolean.valueOf(information.getValue().toString())) {
                            runStatus = 1;
                            deviceMap.put(reDeviceName, new Device(reDeviceName, deviceMap.get(reDeviceName).getRunMount() + 1, deviceMap.get(reDeviceName).getTotalMount()));
                        }else {
                            runStatus = 0;
                        }
                    }
                    if (deviceMap.containsKey(reDeviceName) && "设备状态".equals(information.getClassify()) && information.getInformationName().contains("故障状态")) {
                        if (information.getValue() != null && Boolean.valueOf(information.getValue().toString())) {
                            errorStatus = 1;
                        }else {
                            errorStatus = 0;
                        }
                    }
                    if (deviceStatusMap.containsKey(reDeviceName)
                            && (information.getInformationName().contains("运行状态") || information.getInformationName().contains("故障状态"))
                            && errorStatus != -1) {
                        List<DeviceStatus> statusList = deviceStatusMap.get(reDeviceName);
                        for (DeviceStatus deviceStatus : statusList) {
                            if (deviceStatus.getDeviceName().equals(information.getDeviceName())) {
                                deviceStatus.setStatus(errorStatus == 1 ? 2 : runStatus);
                            }
                        }
                    }
                }

//					for (String k : deviceMap.keySet()) {
//						Device device = new Device(k, deviceMap.get(k).getRunMount(), deviceMap.get(k).getTotalMount());
//						devices.add(device);
//					}
                List<Device> devices = new ArrayList<>(deviceMap.values());

                Map<String, Object> res = new HashMap<>();
                res.put("sensors", modBusDevice.getSensorInfoList());
                res.put("devices", resList);
                res.put("deviceMount", devices);
                res.put("status",deviceStatusMap);
                String json = JsonUtil.toJson(new ResponseResult<>(res));
                // 发送 JSON 数据给客户端
                pushFirstViewData(json);
            } catch (Exception e) {
                logger.error("首页 MODBUS 发送数据失败" + e);
            }


        } catch (Exception e) {
            logger.error("打开串口连接出错", e);
        }
    }

    @Async
    synchronized void dealAlarm(ModBusDevice modBusDevice) throws Exception {

        System.out.println("异步方法处理");

        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        for (Information information : modBusDevice.getInformationList()) {
            if ("设备状态".equals(information.getClassify()) && information.getInformationName().contains("故障状态")) {
                Alarm alarm = new Alarm();
                alarm.setSource(information.getDeviceName());
                alarm.setAlarmTime(formatter.format(new Date().getTime()));
                alarm.setMessage(information.getInformationName());
                Alarm oldAlarm = informationService.getAlarmInfo(alarm);//有就不存
                logger.info(information.getDeviceName() + "设备当前报警状态" + information.getValue());

                if (information.getValue() != null && (Boolean) information.getValue()) {//判断报警状态
                    //存入报警表
                    logger.warn("有设备报警：" + information.getDeviceName() + "modbus:" + information.getModbus());
                    if (oldAlarm == null) {
                        informationService.addAlarm(alarm);
                        String alarmRes = JsonUtil.toJson(new ResponseResult<>(alarm));
                        pushAlarmData(alarmRes);//发生报警信息到前端
                        pushAlarmData(alarmRes);//发生报警信息到前端
                    }
                } else {
                    //有记录则修改设备恢复时间
                    Alarm oldAlarmInfo = informationService.getOldAlarmInfo(alarm);
                    if (oldAlarmInfo != null) {
                        oldAlarmInfo.setRenewTime(formatter.format(new Date().getTime()));
                        oldAlarmInfo.setIsAlarm(0);
                        informationService.updateRenewTime(oldAlarmInfo);
                    }
                }

            }
        }


    }

    private void test() throws ModbusTransportException, ErrorResponseException, ModbusInitException, ExecutionException, InterruptedException {
        List<Information> list = informationMapper.getTest();
        ConcurrentHashMap<String, Modbus4jUtils> modbusList = ConfigCache.modbusList;
        SimpleMasterExample simpleMasterExample = new SimpleMasterExample("211.154.22.175");
        simpleMasterExample.initModbusTcpMaster("211.154.22.175");

        for (Information item : list) {
//			if(item.getModbus()>40000){
//				//System.out.println(item.getModbus());
//				try {
//					simpleMasterExample.readHoldingRegisters(item.getModbus()-40000, 2, 1);
//
//				}catch (Exception e){
//					System.out.println(item.getModbus()+"ERROR");
//				}
//
//			}
//
//			if(item.getModbus()>20000&&item.getModbus()<40000){
//				//System.out.println(item.getModbus());
//				try {
//					simpleMasterExample.readInputRegisters(item.getModbus()-30000, 2, 1);
//
//				}catch (Exception e){
//					System.out.println(item.getModbus()+"ERROR");
//				}
//
//			}

            if (item.getModbus() < 10000) {
                System.out.println(item.getModbus());
                try {

                    System.out.println(simpleMasterExample.readCoils(1000 - item.getModbus(), 2, 1));
                } catch (Exception e) {
                    System.out.println(item.getModbus() + "ERROR");
                }

            }

        }

    }


    private void pushAlarmData(String message) {
        try {
            CopyOnWriteArraySet<AlarmWebSocket> webSocketSet = AlarmWebSocket.getWebSocketSet();
            webSocketSet.forEach(webSocket -> {
                try {
                    webSocket.sendMessage( /*new Date().toLocaleString()+*/ message); // 发送合并后的消息到 WebSocket
                } catch (Throwable t) {
                    t.printStackTrace();
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void pushFirstViewData(String message) {
        try {
            CopyOnWriteArraySet<MyWebSocket> webSocketSet = MyWebSocket.getWebSocketSet();
            webSocketSet.forEach(webSocket -> {
                try {
                    webSocket.sendMessage( /*new Date().toLocaleString()+*/ message); // 发送合并后的消息到 WebSocket
                } catch (Throwable t) {
                    t.printStackTrace();
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void dealHistory(ModBusDevice modBusDevice) throws InterruptedException {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Thread.sleep(4000);
        System.out.println("记录数据: " + formatter.format(new Date().getTime()));
        //		ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        //		scheduler.scheduleAtFixedRate(() -> {
        //			// 记录数据的逻辑
        //			System.out.println("记录数据: " + System.currentTimeMillis());
        //		}, 0, 10, TimeUnit.SECONDS);
    }


}
